/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2009, Around(J2)ME				                                 **
 **   All rights reserved.                                                   **
 **                                                                          **
 **   This program and the accompanying materials are made available under   **
 **   the terms of the New BSD License which accompanies this    			 **
 **   distribution.											                 **
 **   A copy is found in the textfile LICENSE.txt							 **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Main developers:                                                       **
 **     Juri Strumpflohner		http://blog.js-development.com	             **
 **		Matthias Braunhofer		http://matthias.jimdo.com                    **
 **                                                                          **
 **  **********************************************************************  */

package com.aroundj2me.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

import com.aroundj2me.utility.Constants;

/**
 * This class is responsible for encoding the responses (which are
 * send back to the client) into XML and for reading the places from the local XML file
 */
public class XMLManager {
	private Document doc;
	private String continent;
	
	public XMLManager(String continent){
		this.continent = continent;
	}
	
	/**
	 * loads the XML file into memory
	 * @param input
	 * @throws JDOMException
	 * @throws IOException
	 */
	private void loadDoc(InputStream input) throws JDOMException, IOException {
		SAXBuilder builder = new SAXBuilder();
		doc = builder.build(input);
	}
	
	/**
	 * reads all places from the local XML file that match the specified continent
	 * @param input
	 * @return
	 * @throws JDOMException
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public List<Place> readPlaces(InputStream input) throws JDOMException, IOException {
		loadDoc(input);
		List<Place> places = new ArrayList<Place>();
		List placesElements = getElementsByQuery("//place[continent=\"" + continent + "\"]");
		for (Iterator iterator = placesElements.iterator(); iterator.hasNext();) {
			Element placeElement = (Element)iterator.next();
			String name = placeElement.getChildText("name");
			String address = placeElement.getChildText("address");
			String postalCode = placeElement.getChildText("postalCode");
			String city = placeElement.getChildText("city");
			String country = placeElement.getChildText("country");
			String continent = placeElement.getChildText("continent");
			String phone = placeElement.getChildText("phone");
			String url = placeElement.getChildText("url");
			List<String> categories = parseCategories(placeElement);
			double lat = Double.valueOf(placeElement.getChild("location").getChildText("lat"));
			double lon = Double.valueOf(placeElement.getChild("location").getChildText("lon"));
			Place place = new Place(name, address, postalCode, city, country, continent, phone, url, categories, lat, lon);
			places.add(place);
		}
		return places;
	}
	
	@SuppressWarnings("unchecked")
	private List<String> parseCategories(Element element) {
		List<String> categories = new ArrayList<String>();
		List categoryElements = element.getChild("categories").getChildren();
		for (Iterator iterator = categoryElements.iterator(); iterator.hasNext();) {
			Element categoryElement = (Element)iterator.next();
			String category = categoryElement.getText();
			categories.add(category);
		}
		return categories;
	}

	@SuppressWarnings("unchecked")
	private List getElementsByQuery(String xPath) throws JDOMException  {
		XPath path = XPath.newInstance(xPath);
		return path.selectNodes(doc);
	}
	
	/**
	 * Creates a new instance of Document and
	 * adds a root element to it
	 *
	 */
	private void createNewDoc(){
		Element root = new Element("root");
		doc = new Document();
		doc.setRootElement(root);
	}
	
	/**
	 * 
	 * @param type
	 */
	private void setDocType(String type){
		Element typeEl = new Element("type");
		typeEl.setText(type);
		doc.getRootElement().addContent(typeEl);
	}
	
	/**
	 * 
	 * @param size
	 */
	private void setDocSize(int size) {
		Element sizeEl = new Element("size");
		sizeEl.setText(String.valueOf(size));
		doc.getRootElement().addContent(sizeEl);
	}
	
	/**
	 * Creates a new BodyElement, adds it to the root
	 * and returns it for further editing
	 * @return
	 */
	private Element createAndAddBodyElement(){
		Element bodyEl = new Element("responseBody");
		doc.getRootElement().addContent(bodyEl);
		return bodyEl;
	}
	
	/**
	 * Encodes a list of places into XML
	 * @param places Places to be encoded
	 * @return String containing the places encoded in the XML file
	 */
	public String encodePlacesToXML(List<Place> places){
		createNewDoc();
		setDocType(Constants.DATA_PLACES);
		setDocSize(places.size());
		
		Element bodyEl = createAndAddBodyElement();
		
		for (Place place : places) {
			bodyEl.addContent(createPlaceElement(place));
		}
		
		return createXMLString();
	}
	
	private Element createPlaceElement(Place place){
		Element placeEl = new Element("place");
		Element nameEl = new Element("name");
		nameEl.setText(place.getName());
		Element addressEl = new Element("address");
		addressEl.setText(place.getAddress());	
		Element postalCodeEl = new Element("postalCode");
		postalCodeEl.setText(place.getPostalCode());
		Element cityEl = new Element("city");
		cityEl.setText(place.getCity());
		Element countryEl = new Element("country");
		countryEl.setText(place.getCountry());
		Element continentEl = new Element("continent");
		continentEl.setText(place.getContinent());
		Element phoneEl = new Element("phone");
		phoneEl.setText(place.getPhone());
		Element urlEl = new Element("url");
		urlEl.setText(place.getUrl());
		Element categoriesEl = new Element("categories");
		for (String category : place.getCategories()) {
			Element categoryEl = new Element("category");
			categoryEl.setText(category);
			categoriesEl.addContent(categoryEl);
		}
		
		Element locationEl = new Element("location");
		Element latEl = new Element("lat");
		latEl.setText(String.valueOf(place.getLat()));
		Element lonEl = new Element("lon");
		lonEl.setText(String.valueOf(place.getLon()));
		
		placeEl.addContent(nameEl);
		placeEl.addContent(addressEl);
		placeEl.addContent(postalCodeEl);
		placeEl.addContent(cityEl);
		placeEl.addContent(countryEl);
		placeEl.addContent(continentEl);
		placeEl.addContent(phoneEl);
		placeEl.addContent(urlEl);
		placeEl.addContent(categoriesEl);
		placeEl.addContent(locationEl);
		locationEl.addContent(latEl);
		locationEl.addContent(lonEl);

		return placeEl;
	}

	/**
	 * Encodes an alert into XML
	 * @param alertType Type of the Alert (info, error)
	 * @param message Message of the Alert
	 * @return String containing the Alert encoded in XML
	 */
	public String encodeAlert(String alertType, String message){
		createNewDoc();
		setDocType(Constants.ALERT);
		setDocSize(0);
		
		Element bodyEl = createAndAddBodyElement();
		Element alertLevelEl = new Element("level");
		alertLevelEl.setText(alertType);
		Element messageEl = new Element("message");
		messageEl.setText(message);
		
		bodyEl.addContent(alertLevelEl);
		bodyEl.addContent(messageEl);
		
		return createXMLString();
	}
	
	/**
	 * Creates a string out of the JDom document model
	 * @return String containing the whole XML in the Document object
	 */
	private String createXMLString(){
//		doc.setDocType(new DocType("html", "-//W3C//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict.dtd"));
		Format f = Format.getCompactFormat();
		f.setEncoding("ISO-8859-1");
		XMLOutputter outputter = new XMLOutputter(f);
		return outputter.outputString(doc);
	}
}
